package sg.edu.nus.iss.billing.gui.subscription;



import static sg.edu.nus.iss.billing.localization.MessageKeyManager.getMessage;

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;

import javax.swing.AbstractButton;
import javax.swing.ButtonGroup;
import javax.swing.ButtonModel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;

import sg.edu.nus.iss.billing.controller.ServiceController;
import sg.edu.nus.iss.billing.controller.SubscriptionController;
import sg.edu.nus.iss.billing.entity.RecordState;
import sg.edu.nus.iss.billing.entity.service.BasicChoicable;
import sg.edu.nus.iss.billing.entity.service.Callable;
import sg.edu.nus.iss.billing.entity.service.DigitalVoiceService;
import sg.edu.nus.iss.billing.entity.service.MobileVoiceService;
import sg.edu.nus.iss.billing.entity.service.PackageService;
import sg.edu.nus.iss.billing.entity.service.RateChargable;
import sg.edu.nus.iss.billing.entity.service.Service;
import sg.edu.nus.iss.billing.entity.service.SubscriptionEntity;
import sg.edu.nus.iss.billing.entity.service.ValueAddedService;
import sg.edu.nus.iss.billing.exception.ControllerException;
import sg.edu.nus.iss.billing.exception.ValidationException;
import sg.edu.nus.iss.billing.gui.component.ErrorDialog;
import sg.edu.nus.iss.billing.util.UniqueKeyGenerator;
import sg.edu.nus.iss.billing.util.Util;
import sg.edu.nus.iss.billing.validation.ValidationRule;

/**
 * 
 * @author RAJU NAVANEETHAM VENKATESHWARI
 *
 */
public class SubcriptionPanel extends SubscriptionTemplatePanel {

	private static final long serialVersionUID = -6264658783708998394L;

	private String accNo;

	private PackageService currentSvc = null;

	private SubscriptionEntity currentSubscribedPkg;

	private SubscriptionController ctl;

	private ServiceController svcCtl;

	/**
	 * 
	 * @param forPkgSvc decide which plan view will display
	 * @param currentSubscribedPkg
	 */
	public SubcriptionPanel(String accNo, PackageService forPkgSvc) {
		
		super();
		this.accNo = accNo;
		this.currentSvc = forPkgSvc;
		ctl = new SubscriptionController();
		svcCtl = new ServiceController();
		initData();
		initGUI();
		initViewModel();
	}

	public SubcriptionPanel(String accNo, PackageService forPkgSvc, boolean isViewModel) {

		super();
		super.setViewModel(isViewModel);
		this.accNo = accNo;
		this.currentSvc = forPkgSvc;
		ctl = new SubscriptionController();
		svcCtl = new ServiceController();
		initData();
		initGUI();
		initViewModel();
	}

	public void refreshUI() {

		this.removeAll();
		setSubscribedRadios(new ButtonGroup());
		initData();
		initGUI();
		this.updateUI();
	}

	@Override
	protected void initGUI() {
		super.initGUI();
		
		if (isCallable()) {
			String number = "";
			if(currentSubscribedPkg != null){
				number = currentSubscribedPkg.getSvcNo() == null ?"":currentSubscribedPkg.getSvcNo();
			}
			getSvcNoTxt().setText(number);
			if(!Util.isEmpty(number)){
				getSvcNoTxt().setEditable(false);
				
			}
			getPhoneNoGenBtn().addActionListener(new NumberGenerate());
		}
		
		if(currentSubscribedPkg != null){
			String startDt = "";
			String endDt = "";
			Date tempDt = currentSubscribedPkg.getSubscribeDt();
			startDt = (tempDt == null) ?"":Util.getStringFromdate(tempDt);
			tempDt = currentSubscribedPkg.getTerminateDt();
			endDt = (tempDt == null) ?"":Util.getStringFromdate(tempDt);
			getPlanSubscribedDtTxt().setText(startDt);
			getPlanTerminateDtTxt().setText(endDt);
		}
		
		// select first radio button
		Enumeration<AbstractButton> enumer = getSubscribedRadios().getElements();
		try {
			while (enumer.hasMoreElements()) {
				AbstractButton btn = enumer.nextElement();
				String pkgSvcName = btn.getActionCommand();
				if (currentSubscribedPkg!=null) {
					String temp = svcCtl.getServiceById(currentSubscribedPkg.getSvcId()).getServiceName();

					if (pkgSvcName.equals(temp)) {
						((JRadioButton) btn).setSelected(true);
						displaySubscibedPakSvc(currentSubscribedPkg);
						break;
					}
				} else {
					((JRadioButton) btn).setSelected(true);
					displayUnsubscribedPakSvc(getDisplaySvcByName(pkgSvcName));
					break;
				}
			}
		} catch (ControllerException e) {
			e.printStackTrace();
			ErrorDialog.showControllerErrorMessageDialog(e);
		}
	}

	@SuppressWarnings("unchecked")
	private void initData() {

		getSubscribedVAS().clear();
		getUnsibscribedVAS().clear();
		getSubscribedBasicSvc().clear();
		getUnsibscribedBasicSvc().clear();
		setDisplayPakSvcs(new ArrayList<PackageService>());

		try {
			// init the current subscribed svc
			List<SubscriptionEntity> subPakSvcs = ctl.getSubscribedPakSvcByAccNo(accNo);
			if (Util.isEmpty(subPakSvcs)) {
				currentSubscribedPkg = null;
			} else {
				for (SubscriptionEntity subPak : subPakSvcs) {
					PackageService pak = (PackageService) svcCtl.getServiceById(subPak.getSvcId());
					if (pak.getClass()==currentSvc.getClass()) {
						currentSubscribedPkg = subPak;
						break;
					}
				}
			}

			// init the display package
			List<ValueAddedService> vas = new ArrayList<ValueAddedService>();
			List<ValueAddedService> basicSvc = new ArrayList<ValueAddedService>();
			List<SubscriptionEntity> subs = new ArrayList<SubscriptionEntity>();
			List<SubscriptionEntity> basicSubs = new ArrayList<SubscriptionEntity>();

			if (currentSubscribedPkg!=null) {
				currentSvc = (PackageService) svcCtl.getServiceById(currentSubscribedPkg.getSvcId());
				subs = ctl.getVASSubscriptions(currentSubscribedPkg.getId());
				basicSubs = ctl.getBasicSubscriptions(currentSubscribedPkg.getId());
				getDisplayPakSvcs().add(currentSvc);
			} else {
				setDisplayPakSvcs((List<PackageService>) svcCtl.getAllPkgSvcs(currentSvc));
				if(Util.isEmpty(currentSvc.getServiceProductID())){
					currentSvc = getDisplayPakSvcs().get(0);
				}
			}

			// init the additional service data

			if (!Util.isEmpty(currentSvc.getServiceProductID())) {
				vas = svcCtl.getVAServicesByProductId(currentSvc.getServiceProductID());
				basicSvc = svcCtl.getBasicServicesByProductId(currentSvc.getServiceProductID());
			}

			if (!Util.isEmpty(vas)) {
				for (ValueAddedService v : vas) {
					getUnsibscribedVAS().put(v.getId(), v);
				}
			}
			if (!Util.isEmpty(basicSvc)) {
				for (ValueAddedService v : basicSvc) {
					getUnsibscribedBasicSvc().put(v.getId(), v);
				}
			}

			if (!Util.isEmpty(subs)) {
				for (SubscriptionEntity s : subs) {
					getSubscribedVAS().put(s.getSvcId(), s);
					getUnsibscribedVAS().remove(s.getSvcId());
				}
			}
			if (!Util.isEmpty(basicSubs)) {
				for (SubscriptionEntity s : basicSubs) {
					getSubscribedBasicSvc().put(s.getSvcId(), s);
					getUnsibscribedBasicSvc().remove(s.getSvcId());
				}
			}
			
			if (currentSvc instanceof Callable) {
				setCallable(true);
				if(currentSvc instanceof DigitalVoiceService){
					getSvcNoTxt().setRules(ValidationRule.LAND_LINE);
				}
			} else {
				setCallable(false);
			}
			
			if (currentSvc instanceof RateChargable) {
				setRateable(true);
			} else {
				setRateable(false);
			}
			
			if (currentSvc instanceof BasicChoicable) {
				setChoicable(true);
			} else {
				setChoicable(false);
			}
			
		} catch (ControllerException e) {
			e.printStackTrace();
			ErrorDialog.showControllerErrorMessageDialog(e);
		}

	}

	private PackageService getDisplaySvcByName(String name) {

		if (!Util.isEmpty(name)&&!Util.isEmpty(getDisplayPakSvcs())) {
			for (PackageService svc : getDisplayPakSvcs()) {
				if (svc.getServiceName().equals(name))
					return svc;
			}
		}
		return null;
	}

	protected void displayUnsubscribedPakSvc(Service plan) {

		List<ValueAddedService> vas = null;
		try {
			vas = svcCtl.getVAServicesByProductId(plan.getServiceProductID());
		} catch (ControllerException e) {
			e.printStackTrace();
			ErrorDialog.showControllerErrorMessageDialog(e);
		}

		if (isShowBasicSvc()) {
			getBasicSvcViewPanel().removeAllRow();
			if (!Util.isEmpty(getUnsibscribedBasicSvc())) {
				int i = 0;
				for (Map.Entry<String, ValueAddedService> entry : getUnsibscribedBasicSvc().entrySet()) {
					if (isChoicable()) {
						getBasicSvcViewPanel().setBasicChociable(true);
						getBasicSvcViewPanel().addRow(++i, entry.getValue(), null, null, false);
					} else {
						getBasicSvcViewPanel().addRow(++i, entry.getValue(), null, null, true);
					}
					
				}
			}
		}

		getAddiSvcViewPanel().removeAllRow();
		if (!Util.isEmpty(vas)) {
			for (int i = 0; i<vas.size(); i++) {
				getAddiSvcViewPanel().addRow(i+1, vas.get(i), null, null, false);
			}
		}

		this.getPlanSubscribedDtTxt().setText(Util.getStringFromdate(new Date()));
		this.getPlanSubscribedDtTxt().setEditable(true);
		this.getPlanTerminateDtTxt().setText("");
		this.getSubsFeeTxt().setText(plan.getFixedMonthlyCharge().toString());

	}

	protected void displaySubscibedPakSvc(SubscriptionEntity sub) {

		try {
			Service pakSvc = svcCtl.getServiceById(sub.getSvcId());

			BigDecimal subscribeFee = pakSvc.getFixedMonthlyCharge();
			String planStartDt = sub.getSubscribeDt()==null ? "" : Util.getStringFromdate(sub.getSubscribeDt());
			String planEndDt = sub.getTerminateDt()==null ? "" : Util.getStringFromdate(sub.getTerminateDt());

			int currentRow = 0;
			if (isShowBasicSvc()) {
				getBasicSvcViewPanel().removeAllRow();

				if (!Util.isEmpty(this.getSubscribedBasicSvc())) {
					for (Map.Entry<String, SubscriptionEntity> entry : getSubscribedBasicSvc().entrySet()) {
						Service svc = svcCtl.getServiceById(entry.getValue().getSvcId());
						getBasicSvcViewPanel().addRow(++currentRow, svc, sub.getSubscribeDt(), sub.getTerminateDt(), true);
					}
				}
				if (!isViewModel()) {
					if (!Util.isEmpty(this.getUnsibscribedBasicSvc())) {
						for (Map.Entry<String, ValueAddedService> entry : getUnsibscribedBasicSvc().entrySet()) {
							if(isChoicable()){
								getBasicSvcViewPanel().addRow(++currentRow, entry.getValue(), sub.getSubscribeDt(), sub.getTerminateDt(), false);
							} else {
								getBasicSvcViewPanel().addRow(++currentRow, entry.getValue(), sub.getSubscribeDt(), sub.getTerminateDt(), true);
							}
						}
					}
				}
			}

			getAddiSvcViewPanel().removeAllRow();
			currentRow = 0;
			if (!Util.isEmpty(getSubscribedVAS())) {
				for (SubscriptionEntity subscription : getSubscribedVAS().values()) {
					if(isViewModel()){
						if(subscription.getState() != RecordState.ACTIVE){
							continue;
						}
					}
					Service svc = svcCtl.getServiceById(subscription.getSvcId());
					getAddiSvcViewPanel().addRow(++currentRow, svc, subscription.getSubscribeDt(), subscription.getTerminateDt(), true);
				}
			}

			if (!Util.isEmpty(getUnsibscribedVAS())) {
				for (Service svc : getUnsibscribedVAS().values()) {
					getAddiSvcViewPanel().addRow(++currentRow, svc, null, null, false);
				}
			}

			// if (pakSvc instanceof RateChargable) {
			// this.rateTypeTxt.setText(((RateChargable)
			// pakSvc).getRateUnit().toString());
			// this.rateTxt.setText(((RateChargable)
			// pakSvc).getServiceRate().toString());
			// }
			this.getPlanSubscribedDtTxt().setText(planStartDt);
			this.getPlanSubscribedDtTxt().setEditable(false);
			this.getPlanTerminateDtTxt().setText(planEndDt);
			this.getSubsFeeTxt().setText(subscribeFee.toString());
		} catch (ControllerException e) {
			e.printStackTrace();
			ErrorDialog.showControllerErrorMessageDialog(e);
		}

	}

	private void initViewModel() {

		if (isViewModel()) {
			Component[] coms = this.getComponents();
			for (Component c : coms) {
				if (c instanceof JTextField) {
					((JTextField) c).setEditable(false);
				}
			}
		}
	}

	
	private class NumberGenerate implements ActionListener{

		@Override
		public void actionPerformed(ActionEvent e) {
			if(getSvcNoTxt().isEditable()){
				if(currentSvc instanceof MobileVoiceService){
					getSvcNoTxt().setText(UniqueKeyGenerator.createUniqueMobileVoiceNo());
				} else if(currentSvc instanceof DigitalVoiceService){
					getSvcNoTxt().setText(UniqueKeyGenerator.createUniqueDigitalVoiceNo());
				}
			}
			
		}
		
	}


	public boolean deSubscribePlan() {
		boolean result = false;
		if (currentSubscribedPkg!=null) {
			try {
				ctl.desubscribe(currentSubscribedPkg);
				result = true;
			} catch (ControllerException e1) {
				e1.printStackTrace();
				ErrorDialog.showControllerErrorMessageDialog(e1);
				result = false;
			}
			
		} else {
			//is possible
		}
		return result;
	}

	public boolean subscribePlan() {
		boolean result = false;
		try {
			ButtonModel selectedSub = getSubscribedRadios().getSelection();
			if (selectedSub!=null) {
				String pakName = selectedSub.getActionCommand();
				PackageService newSvcPak = null;

				newSvcPak = getDisplaySvcByName(pakName);

				SubscriptionEntity pakSvcSubs = new SubscriptionEntity();

				pakSvcSubs.setSvcId(newSvcPak.getId());
				pakSvcSubs.setAccNo(accNo);
				pakSvcSubs.setSubscribeDt(Util.getDateFromString(getPlanSubscribedDtTxt().getValidatedText()));// planSubscribedDtTxt
				pakSvcSubs.setTerminateDt(Util.getDateFromString(getPlanTerminateDtTxt().getValidatedText()));// planTerminateDtTxt
				pakSvcSubs.setState(RecordState.ACTIVE);
				if(isCallable()) {
					pakSvcSubs.setSvcNo(getSvcNoTxt().getValidatedText());
				}

				List<SubscriptionEntity> svcs = new ArrayList<SubscriptionEntity>();
				if (isShowBasicSvc()) {
					List<String[]> newBasicSvc = getBasicSvcViewPanel().getNewRegisteredServices();
					if (isChoicable()) {
						int count = ((BasicChoicable) currentSvc).getBasicSvcChoiceCount();
						if (count!=newBasicSvc.size()) {
							throw new ValidationException(getMessage("error.subs.subscribedcount.notmatch", String.valueOf(count)));
						}
					}
					for (String[] data : newBasicSvc) {
						SubscriptionEntity newSub = new SubscriptionEntity();
						newSub.setState(RecordState.ACTIVE);
						newSub.setBasicSvc(true);
						newSub.setSvcId(data[0]);
						newSub.setSubscribeDt(Util.getDateFromString(getPlanSubscribedDtTxt().getText()));
						newSub.setTerminateDt(Util.getDateFromString(getPlanTerminateDtTxt().getText()));
						svcs.add(newSub);
					}
				}
				List<String[]> newAddSvc = getAddiSvcViewPanel().getNewRegisteredServices();
				if (!Util.isEmpty(newAddSvc)) {

					for (String[] data : newAddSvc) {
						SubscriptionEntity newSub = new SubscriptionEntity();
						newSub.setState(RecordState.ACTIVE);
						newSub.setSvcId(data[0]);
						if (Util.isEmpty(data[1])) {
							newSub.setSubscribeDt(Util.getCurrentDate());
						} else {
							newSub.setSubscribeDt(Util.getDateFromString(data[1]));
						}
						newSub.setTerminateDt(Util.getDateFromString(data[2]));
						svcs.add(newSub);
					}
				}

				ctl.saveSubscription(pakSvcSubs, svcs);
				result = true;
				
			}
		} catch (ControllerException e1) {
			ErrorDialog.showControllerErrorMessageDialog(e1);
		} catch (ValidationException e) {
			ErrorDialog.showValidationErrorMessageDialog(e);
		}
		return result;

	}

	public boolean updatePlan() {
		boolean result = false;
		if (currentSubscribedPkg!=null) {
			currentSubscribedPkg.setTerminateDt(Util.getDateFromString(getPlanTerminateDtTxt().getText()));
			try {
				List<SubscriptionEntity> saveList = new ArrayList<SubscriptionEntity>();
				if (isShowBasicSvc()) {
					saveList.addAll(getUpdateSubscription(currentSubscribedPkg, getBasicSvcViewPanel(), true));
				}
				saveList.addAll(getUpdateSubscription(currentSubscribedPkg, getAddiSvcViewPanel(), false));

				ctl.saveSubscription(currentSubscribedPkg, saveList);
				result = true;
			} catch (ControllerException e1) {
				e1.printStackTrace();
				ErrorDialog.showControllerErrorMessageDialog(e1);
			} catch (ValidationException e) {
				ErrorDialog.showValidationErrorMessageDialog(e);
			}
		} else {
			//TODO:is possible?
		}
		return result;
	}

	private List<SubscriptionEntity> getUpdateSubscription(SubscriptionEntity plan, ServiceViewPanel svcViewPanel, boolean isBasicSvc) throws ValidationException {

		List<SubscriptionEntity> saveList = new ArrayList<SubscriptionEntity>();
		if (plan!=null) {

			List<String[]> newSvc = svcViewPanel.getNewRegisteredServices();
			List<String[]> modifiedSvc = svcViewPanel.getModifiedRegisteredServices();
			List<String> deregisteredSvc = svcViewPanel.getDeregisteredServices();

			if (!Util.isEmpty(newSvc)) {

				for (String[] data : newSvc) {
					SubscriptionEntity newSub = new SubscriptionEntity();
					newSub.setState(RecordState.ACTIVE);
					newSub.setSvcId(data[0]);
					newSub.setBasicSvc(isBasicSvc);
					if (Util.isEmpty(data[1])) {
						newSub.setSubscribeDt(Util.getCurrentDate());
					} else {
						newSub.setSubscribeDt(Util.getDateFromString(data[1]));
					}
					newSub.setTerminateDt(Util.getDateFromString(data[2]));
					saveList.add(newSub);
				}
			}
			if (!Util.isEmpty(modifiedSvc)) {
				for (String[] data : modifiedSvc) {
					SubscriptionEntity sub = null;
					if (isBasicSvc) {
						sub = getSubscribedBasicSvc().get(data[0]);
					} else {
						sub = getSubscribedVAS().get(data[0]);
					}

					// TODO:change to data latter
					sub.setTerminateDt(Util.getCurrentDate());// data[1]
					saveList.add(sub);
				}
			}

			if (!Util.isEmpty(deregisteredSvc)) {
				for (String svcId : deregisteredSvc) {
					
					SubscriptionEntity sub = null;
					if (isBasicSvc) {
						sub = getSubscribedBasicSvc().get(svcId);
					} else {
						sub = getSubscribedVAS().get(svcId);
					}
					sub.setTerminateDt(Util.getCurrentDate());
					sub.setState(RecordState.DELETED);
					saveList.add(sub);
				}
			}

			if (saveList!=null && isBasicSvc && isChoicable()) {
				int count = ((BasicChoicable) currentSvc).getBasicSvcChoiceCount();
				if (count!=svcViewPanel.getSelectedCount()) {
					throw new ValidationException(getMessage("error.subs.subscribedcount.notmatch", String.valueOf(count)));
				}
			}
		}
		return saveList;
	}

	@Override
	protected void handlePlanSwitch(ActionEvent e) {
		JRadioButton radio = (JRadioButton) e.getSource();
		String pkgSvcName = e.getActionCommand();
		if (radio.isSelected()) {
			if (currentSubscribedPkg!=null) {
				displaySubscibedPakSvc(currentSubscribedPkg);
			} else {
				for (Service svc : getDisplayPakSvcs()) {
					if (svc.getServiceName().equals(pkgSvcName)) {
						currentSvc = (PackageService) svc;
						initData();
						displayUnsubscribedPakSvc(svc);
						break;
					}
				}
			}
		}
	}

}
